//
// Created by RandBII on 2020/12/24.
//

#include <render/video/NativeRender.h>
#include "FFmpegMediaPlayer.h"

void FFmpegMediaPlayer::Init(JNIEnv *env, jobject obj, char *url, int renderType, jobject surface) {
    env->GetJavaVM(&mJavaVM);
    mJavaObj = env->NewGlobalRef(obj);

    videoDecoder = new VideoDecoder(url);
    audioDecoder = new AudioDecoder(url);

    switch (renderType) {
        case VIDEO_RENDER_ANWINDOW:
            videoRender = new NativeRender(env, surface);
            videoDecoder->SetVideoRender(videoRender);
            break;
        case VIDEO_RENDER_OPENGL:
            //  TODO 待补充
            LOG_E("FFmpegMediaPlayer::Init 待补充");
            break;
        case VIDEO_RENDER_3D_VR:
            //  TODO 待补充
            LOG_E("FFmpegMediaPlayer::Init 待补充");
            break;
        default:
            LOG_E("FFmpegMediaPlayer::Init renderType is not exist renderType : %d", renderType);
            break;
    }
    audioRender = new OpenSLRender();
    audioDecoder->SetAudioRender(audioRender);

    videoDecoder->SetMessageCallback(this, PostMessage);
    audioDecoder->SetMessageCallback(this, PostMessage);

}

void FFmpegMediaPlayer::UnInit() {
    if (videoDecoder) {
        delete videoDecoder;
        videoDecoder = nullptr;
    }
    if (videoRender) {
        delete videoRender;
        videoRender = nullptr;
    }

    if (audioRender) {
        delete audioRender;
        audioRender = nullptr;
    }

    //TODO
    bool isAttack = false;
    GetJNIEnv(&isAttack)->DeleteGlobalRef(mJavaObj);
    if (isAttack) {
        GetJavaVM()->DetachCurrentThread();
    }


}

void FFmpegMediaPlayer::Play() {
    if (videoDecoder) videoDecoder->Start();
    if (audioDecoder) audioDecoder->Start();
}

void FFmpegMediaPlayer::Pause() {
    if (videoDecoder) videoDecoder->Pause();
    if (audioDecoder) audioDecoder->Pause();
}

void FFmpegMediaPlayer::Stop() {
    if (videoDecoder) videoDecoder->Stop();
    if (audioDecoder) audioDecoder->Stop();
}

void FFmpegMediaPlayer::SeekToPosition(float position) {
    if (videoDecoder) videoDecoder->SeekToPosition(position);
    if (audioDecoder) audioDecoder->SeekToPosition(position);
}

long FFmpegMediaPlayer::GetMediaParams(int paramType) {
    long value = 0;
    switch (paramType) {
        case MEDIA_PARAM_VIDEO_WIDTH:
            value = videoDecoder != nullptr ? videoDecoder->GetVideoWidth() : 0;
            break;
        case MEDIA_PARAM_VIDEO_HEIGHT:
            value = videoDecoder != nullptr ? videoDecoder->GetVideoHeight() : 0;
            break;
        case MEDIA_PARAM_VIDEO_DURATION:
            value = videoDecoder != nullptr ? videoDecoder->GetDuration() : 0;
            break;
    }
    return value;
}


JNIEnv *FFmpegMediaPlayer::GetJNIEnv(bool *isAttached) {

    JNIEnv *env;
    int status;

    if (!mJavaVM) {
        LOG_E("FFmpegMediaPlayer::GetJNIEvn mJavaVM is nullptr ");
        return nullptr;
    }
    *isAttached = false;
    status = mJavaVM->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
    if (status != JNI_OK) {
        status = mJavaVM->AttachCurrentThread(&env, nullptr);
        if (status != JNI_OK) {
            LOG_E("FFmpegMediaPlayer::GetJNIEvn failed to attach current thread");
            return nullptr;
        }
    }
    return env;
}

jobject FFmpegMediaPlayer::GetJavaObject() {
    return mJavaObj;
}

JavaVM *FFmpegMediaPlayer::GetJavaVM() {
    return mJavaVM;
}

void FFmpegMediaPlayer::PostMessage(void *context, int msgType, float msgCode) {
    if (context) {
        auto *player = static_cast<FFmpegMediaPlayer *>(context);
        bool isAttach = false;
        JNIEnv *env = player->GetJNIEnv(&isAttach);
        if (!env) {
            LOG_E("FFmpegMediaPlayer::PostMessage get env is null");
            return;
        }
        jobject object = player->GetJavaObject();
        // 非常重要
        jmethodID methodId = env->GetMethodID(env->GetObjectClass(object),
                                              JAVA_PLAYER_EVENT_CALLBACK_API_NAME,
                                              "(IF)Lkotlin/Unit;"
        );
        env->CallVoidMethod(object, methodId, msgType, msgCode);
        if (isAttach) player->GetJavaVM()->DetachCurrentThread();

    }
}
